/*
 * =====================================================================================
 *
 *       Filename:  bdb_test.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  04/01/2011 09:57:27 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Chen Ken (Ken), zlchen.ken@gmail.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#include <iostream>
#include <cstring>
#include <db_cxx.h>

using namespace std;

static const char* dbHome = "/home/nasadmin/work/CPP_LIB/src/db/unit_test";
static const char* dbDataDir = "/home/nasadmin/work/CPP_LIB/src/db/unit_test/data";
static const char* dbFile = "test_bdb.db"; 
static const unsigned int envFlags = DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN | DB_THREAD;
//static const unsigned int dbFlags = DB_CREATE | DB_THREAD;
static const unsigned int dbFlags = DB_AUTO_COMMIT | DB_CREATE | DB_THREAD;
static DBTYPE dbType = DB_HASH;
static DbEnv* dbEnv = NULL; 
static Db* bdb = NULL;

static void createBDB(void)
{
	dbEnv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
	dbEnv->set_data_dir(dbDataDir);
	if(dbEnv->open(dbHome, envFlags, 0) != 0)
	{
		cerr << "DbEnv::open\n";
		exit(1);
	}

#if 0
	DbTxn* tid = NULL;
	if(dbEnv->txn_begin(NULL, &tid, DB_TXN_WAIT) != 0)
	{
		cerr << "DbEnv::txn_begin\n";
		exit(1);
	}
#endif

	int ret = 0;
	bdb = new Db(dbEnv, DB_CXX_NO_EXCEPTIONS);
	if((ret = bdb->open(NULL, dbFile, NULL, dbType, dbFlags, 0)) != 0)
	{
		bdb->err(ret, "Db::open");
		exit(1);
	}

#if 0
	if(tid->commit(0) != 0)
	{
		exit(1);
	}
#endif
}

static void manipulateBDB(void)
{
	const string key1("abc"); const string data1("1234");
	const string key2("bcd");
	const string data2("2345");
	const string key3("cde");
	const string data3("3456");

	Dbt dkey1((void*)(key1.c_str()), key1.size() + 1);
	Dbt ddata1((void*)(data1.c_str()), data1.size() + 1);
	Dbt dkey2((void*)(key2.c_str()), key2.size() + 1);
	Dbt ddata2((void*)(data2.c_str()), data2.size() + 1);
	Dbt dkey3((void*)(key3.c_str()), key3.size() + 1);
	Dbt ddata3((void*)(data3.c_str()), data3.size() + 1);
	Dbt dummyKey((void*)"dummyKey", strlen("dummyKey"));

	int ret = 0;
	if((ret = bdb->put(NULL, &dkey1, &ddata1, DB_NOOVERWRITE)) != 0) 
	{
		bdb->err(ret, "Db->put");
	}

	if((ret = bdb->put(NULL, &dkey2, &ddata2, DB_NOOVERWRITE)) != 0) 
	{
		bdb->err(ret, "Db->put");
	}

	if((ret = bdb->put(NULL, &dkey3, &ddata3, DB_NOOVERWRITE)) != 0) 
	{
		bdb->err(ret, "Db->put");
	}

  char* str = NULL;
	Dbt data;
	data.set_flags(DB_DBT_MALLOC);
	if((ret = bdb->get(NULL, &dkey1, &data, 0)) != 0) 
	{
		bdb->err(ret, "Db->get");
	}
	else
	{
	  str = (char*)data.get_data();
	  cout << str << "\n";
	}

	Dbt data22;
	data22.set_flags(DB_DBT_MALLOC);
	if((ret = bdb->get(NULL, &dkey2, &data22, 0)) != 0) 
	{
		bdb->err(ret, "Db->get");
	}
	else
	{
	  str = (char*)data22.get_data();
	  cout << str << "\n";
	}

	if((ret = bdb->del(NULL, &dkey3, 0)) != 0)
	{
		bdb->err(ret, "Db->del");
	}

	Dbt data23;
	data23.set_flags(DB_DBT_MALLOC);
	if((ret = bdb->get(NULL, &dkey3, &data23, 0)) != 0) 
	{
		bdb->err(ret, "Db->get");
	}
	else
	{
	  str = (char*)data23.get_data();
	  cout << str << "\n";
	}

	Dbt data24;
	data24.set_flags(DB_DBT_MALLOC);
	if((ret = bdb->get(NULL, &dummyKey, &data24, 0)) != 0) 
	{
		bdb->err(ret, "Db->get");
	}
	else
	{
	  str = (char*)data23.get_data();
	  cout << str << "\n";
	}
}

static void queryBDB(void)
{
	int ret = 0;
	unsigned int pagesize = 0;

	if((ret = bdb->get_pagesize(&pagesize)) != 0)
	{
		bdb->err(ret, "Db->get_pagesize");
	}
	else
	{
	  cout << "pagesize: " << pagesize << "\n";
	}

	Dbc* cursorp;
	if((ret = bdb->cursor(NULL, &cursorp, 0)) != 0)
	{
		bdb->err(ret, "Db->cursor");
		exit(1);
	}

	do{
	  Dbt key;
	  Dbt data;
	  //data.set_flags(DB_DBT_MALLOC);
    ret = cursorp->get(&key, &data, DB_NEXT);
		if(ret == 0)
		{
      cout << "key: " << (char*)key.get_data() << "-"
			     << "data:" << (char*)data.get_data() << "\n";
		}
		else
		{
		  bdb->err(ret, "Db->get");
		}
	}while(ret == 0);
}

static void closeBDB(void)
{
	bdb->close(0);
	dbEnv->close(0);
}

int main(int argc, char* argv[])
{
	createBDB();
	manipulateBDB();
	queryBDB();
	closeBDB();

	return 0;
}

